package cn.enn.smart.conf;

import cn.enn.smart.handler.EnnAuthenticationFailureHandler;
import cn.enn.smart.handler.EnnAuthenticationSuccessHandler;
import cn.enn.smart.properties.EnnSecurityProperties;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

@Configuration
@EnableResourceServer
public class EnnResourceServerConfiguration extends ResourceServerConfigurerAdapter {

	@Autowired
	private Set<EnnSecurityConfigurer> securityConfigurers;

	@Autowired
	private EnnSecurityProperties properties;

	@Autowired
	private ClientDetailsService clientDetailsService;

	@Autowired
	private AuthorizationServerTokenServices authorizationServerTokenServices;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Bean
	@ConditionalOnMissingBean(AuthenticationFailureHandler.class)
	public AuthenticationFailureHandler authenticationFailureHandler() {
		return new EnnAuthenticationFailureHandler();
	}

	@Bean
	@ConditionalOnMissingBean(AuthenticationSuccessHandler.class)
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		EnnAuthenticationSuccessHandler ennAuthenticationSuccessHandler = new EnnAuthenticationSuccessHandler();
		ennAuthenticationSuccessHandler.setClientDetailsService(clientDetailsService);
		ennAuthenticationSuccessHandler.setAuthorizationServerTokenServices(authorizationServerTokenServices);
		return ennAuthenticationSuccessHandler;
	}

	@Override
	public void configure(HttpSecurity http) throws Exception {
		// formatter: off
		http.csrf().disable().formLogin().successHandler(authenticationSuccessHandler())
				.failureHandler(authenticationFailureHandler());

		Set<String> processUrls = properties.getValidateCode().getProcessUrls();
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry urlRegistry = http
				.authorizeRequests();

		urlRegistry.antMatchers(processUrls.toArray(new String[0])).permitAll();
		urlRegistry.antMatchers(properties.mobileLoginProperties().getProcessUrl()).permitAll();

		if (CollectionUtils.isNotEmpty(securityConfigurers)) {
			for (EnnSecurityConfigurer securityConfigurer : securityConfigurers) {
				securityConfigurer.setAuthenticationManager(authenticationManager);
				securityConfigurer.configure(http);
			}
		}
		urlRegistry.anyRequest().authenticated();

		// formatter: on
	}
}
